home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / umich / demos / gray.lzh / FLOYD7.C < prev    next >
C/C++ Source or Header  |  1991-05-14  |  8KB  |  375 lines

  1. /* THIS PROGRAM IS WRITTEN BY KLAUS PEDERSEN - micro@imada.ou.dk *\
  2. |* The program NEEDS a ST with High rez monitor, and serverves as*|
  3. \* demostration ONLY.____________________________________________*/
  4.  
  5. #include <tos.h>
  6. #include <stdlib.h>
  7. #include <portab.h>
  8.   
  9. #define ERRWIDTH 1024
  10. #define PLANES 3
  11. #define WORDLINE 40 /* words/line */
  12.  
  13. #define FIXEDNUM 4  /* size of the fixed point numbers */
  14.  
  15. typedef WORD ERRTYP; /* if FIXEDNUM>4 then ERRTYP must be LONG */
  16.  
  17. #define MAXGRAY (( (ERRTYP)256 << FIXEDNUM ) - 1)
  18.  
  19. static ERRTYP Levels[4] = {0, MAXGRAY/3, 2*MAXGRAY/3, MAXGRAY}; 
  20.  
  21.  
  22. WORD    Beta, Width, Height, MaxRandom, Flicker, Zoom, n_levels;
  23. ERRTYP Error1Array[ERRWIDTH], Error2Array[ERRWIDTH], *Error1, *Error2;
  24.  
  25. UWORD Screens[(LONG)PLANES*16000+128]; /* reserve screens */
  26.  
  27.  
  28. WORD myRandom(WORD max)
  29. {static LONG Seed = 0;
  30.     if (max == 0) return 0;
  31.     Seed = (5*Seed + 37);  
  32.     return ((WORD)Seed % max);
  33. }
  34.  
  35.  
  36.  
  37. WORD Laplace(char *Pic)
  38. /* This routine returns 2^FIXEDNUM times the pixel value,
  39.  * Beta is fixed point (x.4 bits) 
  40.  *  The formular is :
  41.  *  (2^FIXEDNUM)*lp
  42.  *      = (2^FIXEDNUM) * P(0,0) 
  43.  *    + ( (2^FIXEDNUM)*BETA/4 ) ; this is the 'Beta' you can set.
  44.  *    * ( 4*P(0,0) - P(-1,0)-P(1,0)-P(0,1)-P(0,-1) ) 
  45.  */
  46. {
  47. return 
  48.     ((ERRTYP)*Pic<<FIXEDNUM)
  49.       + Beta*
  50.       ( (ERRTYP)
  51.       (*Pic<<2) - *(Pic-1) - *(Pic+1) - *(Pic+Width) - *(Pic-Width) );
  52. }
  53.  
  54.  
  55.  
  56. int GenConvPixel(char *pic, WORD x, WORD y)
  57. /*  This rutine converts a point in the 'real' image to
  58.  *    a point in the screen image. The procedure uses error-
  59.  *    diffusion to determine the state of the new pixel.
  60.  *    The Error filter is that of Floyd & Steinberg :
  61.  *                / 1  5  3 \  / 
  62.  *                \ 7  X    / / 16
  63.  * This rutine uses a table of levels to make the convertion
  64.  */
  65. {WORD    i, level;
  66.  ERRTYP q, p, err, diffr, *P_levels;
  67.      if (x == 0 || x == Width-1)
  68.         p = (ERRTYP)*pic<<FIXEDNUM;
  69.     else
  70.     {    p = 7*Error1[x-1] + Error2[x-1] + 5*Error2[x] + 3*Error2[x+1];
  71.         if (y == 0 || y == Height-1 || Beta == 0)
  72.             p += (ERRTYP)*pic<<FIXEDNUM;
  73.         else
  74.             p += Laplace(pic);
  75.     }
  76.     
  77.     /*    add dynamic noise, set the initial difference to infinite */
  78.     diffr = MAXGRAY<<2;
  79.     q = p + (ERRTYP)myRandom(MaxRandom);
  80.     P_levels = &Levels[0];
  81.  
  82.     /* find the level that introduces least error */
  83.     for(i = 0; i < n_levels; i++)
  84.     {    err = q - *P_levels++;
  85.         if (err < 0)
  86.             err = -err;
  87.         if (err < diffr)
  88.         {    diffr = err;
  89.             level = i;
  90.         }
  91.     }
  92.     
  93.     /* Now, calculate the error made by quantisation (without noise) */
  94.     Error1[x] = (p - Levels[level]) >> 4;
  95.  
  96.     return level;
  97. }
  98.  
  99.  
  100. void ClearError(void)
  101. {int i;
  102.  
  103.     Error1 = Error1Array;
  104.     Error2 = Error2Array;
  105.      for(i = 0; i < ERRWIDTH; i++)
  106.          Error1Array[i] = Error2Array[i] = 0;
  107. }
  108.  
  109.  
  110. void NextError(void)
  111. {ERRTYP *tmp;
  112.  
  113.     tmp = Error1; Error1 = Error2; Error2 = tmp;
  114. }
  115.  
  116.     
  117. void Convert2Gray(char *pic)
  118. {LONG    yoffset, wordpos;
  119.  WORD x, y, i, q, NextPix;
  120.  UWORD pix[PLANES], *screen[PLANES];
  121.  char *p, *oldphys;
  122.     Cconws("Converting picture to flicker...\r\n");
  123.     /* initialize screens */
  124.     oldphys = Physbase();
  125.     Setscreen((VOID *)-1, (Screens + 128L), -1);
  126.     screen[0] = Physbase();
  127.     for(i=1; i<PLANES; i++)
  128.         screen[i] = screen[i-1] + 16000L;
  129.     
  130.     yoffset = 0;
  131.     Levels[1] = MAXGRAY/3; /* reinsert 2. element of array */
  132.     ClearError();
  133.     NextPix = 0;
  134.         
  135.     for(y = 0; y < Height; y++)
  136.     {    p = pic + (LONG)y*Width;
  137.         wordpos = yoffset;
  138.  
  139.         for(x = 0; x < Width; x++)
  140.         {    /* first clear first pixel in all planes */
  141.             for (i=0; i<PLANES; pix[i++] <<= 1);
  142.  
  143.             q = GenConvPixel(p + (LONG)x, x, y);
  144.  
  145.             while (q--)  /* update all planes */
  146.             {     /* set the pixel in that plane */
  147.                 pix[NextPix]++;
  148.                 if (++NextPix >= PLANES) NextPix = 0;
  149.             }
  150.             
  151.             /* When 16 pixels is made, then put them on the screen */
  152.             if ((x & 0xf) == 0xf)
  153.             {    for(i = 0; i<PLANES; i++)
  154.                     *(screen[i] + wordpos) = pix[i];
  155.                 wordpos++;
  156.             }
  157.         }
  158.         yoffset += WORDLINE;
  159.         NextError();
  160.         if (Bconstat(2)) break;
  161.     }
  162.     
  163.     /* animate the screens */
  164.     do
  165.     {    for (i=0; i<PLANES; i++)
  166.         {    Vsync();
  167.             Setscreen((VOID *)-1,screen[i],-1);
  168.         }
  169.     } while (!Bconstat(2)); /* until a key have been pressed */
  170.     
  171.     Setscreen((VOID *)-1,oldphys,-1);
  172. }
  173.  
  174.  
  175.  
  176. void SimpleConvert2Gray(char *pic)
  177. {LONG yoffset, wordpos;
  178.  WORD x, y;
  179.  UWORD pix, *screen, *oldphys;
  180.  char *p;
  181.  
  182.     Cconws("Converting picture to mono...\r\n");
  183.  
  184.     /* initialize screen */
  185.     oldphys = Physbase();
  186.     Setscreen((VOID *)-1, (Screens + 128L), -1);
  187.     screen = Physbase();
  188.  
  189.     Levels[1] = MAXGRAY; /* reinsert 2. element of array */
  190.     ClearError();
  191.     yoffset = 0;
  192.     pix = 0;
  193.     
  194.     for(y = 0; y < Height; y++)
  195.     {    p = pic + (LONG)y*Width;
  196.         wordpos = yoffset;
  197.     
  198.         for(x = 0; x < Width; x++)
  199.         {    pix <<= 1;
  200.             if (GenConvPixel(p + (LONG)x, x, y))
  201.                 pix++;
  202.     
  203.             /* When 16 pixels is made, then put them on the screen */
  204.             if ((x & 0xf) == 0xf)
  205.                 screen[wordpos++] = pix;
  206.         }
  207.         yoffset += WORDLINE;
  208.         NextError();
  209.         if (Bconstat(2)) break;
  210.     }
  211.     
  212.     /* wait until a key have been pressed */
  213.     while (!Bconstat(2));
  214.  
  215.     Setscreen((VOID *)-1,oldphys,-1);
  216. }
  217.  
  218.  
  219.  
  220. int LoadPicture(const char *Name, char *Picture)
  221. {int f;
  222.     Cconws("Loading picture\r\n");
  223.     if ( (f = Fopen(Name, 0) ) > 0)
  224.     {    Fseek(82l,f,0);  /* ...skip TIFF header... */
  225.         Fread(f, (LONG)Width*Height, Picture);
  226.         Fclose(f);
  227.         return 0;
  228.     }
  229.     else
  230.         return 1;
  231. }
  232.  
  233.  
  234. /*        1 long          resolution (0=low, 1=medium, 2=high)
  235.  *        16 words        palette
  236.  *        23 longs        reserved for expansion
  237.  *        16000 words     picture data (screen memory)
  238.  */
  239.  
  240. int LoadNEO(const char *Name, char *pic)
  241. {int f,color,gray,i,j,pix;
  242.  WORD Palette[16];
  243.  UWORD Line[80], *LinePoint, plane1,plane2,plane3,plane4;
  244.     Cconws("Loading NEO-picture\r\n");
  245.  
  246.     if ( (f = Fopen(Name, 0) ) > 0)
  247.     {    Fseek(4, f, 0);
  248.         Fread(f, 32, Palette);
  249.         
  250.         /* convert all palette entrys to grayscale */
  251.         for (i=0; i<16; i++)
  252.         {    color = Palette[i];
  253.             gray =   26*((color     ) & 7)
  254.                     + 151*((color >> 4) & 7)
  255.                     +  77*((color >> 8) & 7);
  256.             Palette[i] = 255 - gray/7;
  257.         }
  258.  
  259.         Fseek(4*23, f, 1);
  260.         for(i=0; i<200; i++)
  261.         {    Fread(f, 160, Line);
  262.             LinePoint = Line;
  263.             for(j=0; j<320; j++)
  264.             {    if ((j & 15) == 0)
  265.                 {    plane1 = *LinePoint++;
  266.                     plane2 = *LinePoint++;
  267.                     plane3 = *LinePoint++;
  268.                     plane4 = *LinePoint++;
  269.                 }
  270.                 pix = 0;
  271.                 if (plane1 & 0x8000) pix |= 1;
  272.                 if (plane2 & 0x8000) pix |= 2;
  273.                 if (plane3 & 0x8000) pix |= 4;
  274.                 if (plane4 & 0x8000) pix |= 8;
  275.                 gray  = Palette[pix];
  276.                 if (Zoom)
  277.                 {    *(pic + (LONG)Width) = gray;
  278.                     *pic++ = gray;
  279.                     *(pic + (LONG)Width) = gray;
  280.                 }
  281.                 *pic++ = gray;
  282.                     
  283.                 plane1 <<= 1; plane2 <<= 1;
  284.                 plane3 <<= 1; plane4 <<= 1;
  285.             }
  286.             if (Zoom)
  287.                 pic += (LONG)Width;
  288.         }
  289.         Fclose(f);
  290.         return 0;
  291.     }
  292.     else
  293.         return 1;
  294. }
  295.  
  296.  
  297.  
  298. main(int argc, const char *argv[])
  299. {char    *ScreenBuf;
  300.  const char *p;
  301.  
  302.     Beta = 2;
  303.     MaxRandom =    10;
  304.     Height = 400; Width = 575;
  305.     Flicker = 0;  n_levels = 2;
  306.     
  307.     while (--argc)
  308.     {    switch( *(p = *++argv) )
  309.         {    case 'W':
  310.                 Width = atoi(p+1); break;
  311.             
  312.             case 'H':
  313.                 Height = atoi(p+1); break;
  314.             
  315.             case 'R':
  316.                 MaxRandom = atoi(p+1); break;
  317.             
  318.             case 'L':
  319.                 Beta = atoi(p+1); break;
  320.             
  321.             case 'F':
  322.                 Flicker = atoi(p+1); 
  323.                 if (Flicker)
  324.                     n_levels = 4;
  325.                 else
  326.                     n_levels = 2;
  327.                 break;
  328.                 
  329.             case 'N': /* Load 320x200 pics NEO */
  330.                 Width = 320;
  331.                 Height = 200;
  332.                 Zoom = 0;
  333.                 
  334.             case 'Z': /* Load NEO and zoom to full screen */
  335.                 if (*p == 'Z')
  336.                 {    Width = 640;
  337.                     Height = 400;
  338.                     Zoom = 1;
  339.                 }
  340.                 if ((ScreenBuf = Malloc((LONG)Width*Height)) <= 0)
  341.                     goto Error;
  342.                 if (LoadNEO(p + 1, ScreenBuf))
  343.                     goto Error1; 
  344.                 if (Flicker)
  345.                     Convert2Gray(ScreenBuf);
  346.                 else
  347.                     SimpleConvert2Gray(ScreenBuf);
  348.                 Mfree(ScreenBuf);
  349.                 break;
  350.                 
  351.             case 'T': /* Load TIFF picture */    
  352.                 if ((ScreenBuf = Malloc((LONG)Width*Height)) <= 0)
  353.                     goto Error;
  354.                 if (LoadPicture(p + 1, ScreenBuf))
  355.                     goto Error1;
  356.                 if (Flicker)
  357.                     Convert2Gray(ScreenBuf);
  358.                 else
  359.                     SimpleConvert2Gray(ScreenBuf);
  360.